/*
 * @Author: january.cjy
 * @Date: 2021-09-26 21:12:21
 * @Last Modified by: january.cjy
 * @Last Modified time: 2021-09-30 11:47:32
 */
#include "clang/AST/ASTConsumer.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Syntax/BuildTree.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"

#include <iostream>
#include <string>
#include <thread>
#include <unordered_set>

#include <CmgASTFrontendAction.h>
#include <CmgOptionsParser.h>
#include <ThreadPool.h>
#include <util.h>
using namespace std;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
using namespace cmg;

static cl::OptionCategory CmgCategory("cmg options");
// static const opt::OptTable &Options = getDriverOptTable();
// static cl::opt<bool>
//     ASTDump("ast-dump",
//             cl::desc(Options.getOptionHelpText(options::OPT_ast_dump)),
//             cl::cat(CmgCategory));

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

  CmgOptionsParser OptionsParser{argc, argv, CmgCategory};

  auto &Compilations = OptionsParser.getCompilations();
  clang::CommentOptions::BlockCommandNamesTy SourcePathList{
      OptionsParser.getSourcePathList()};

  if (SourcePathList.empty()) {
    auto CompileCommands = Compilations.getAllCompileCommands();
    for (auto command : CompileCommands) {
      SourcePathList.emplace_back(command.Filename);
    }
  }
  util::RemoveRepetition(SourcePathList);
  // for (auto file : SourcePathList) {
  //   llvm::outs() << file << "\n";
  // }

  ThreadPool pool(OptionsParser.getConcurrentJobs());
  vector<future<int>> results;
  for (auto &file : SourcePathList) {
    results.emplace_back(pool.enqueue([&Compilations, &file] {
      ClangTool Tool(Compilations,
                     clang::CommentOptions::BlockCommandNamesTy{file});
      return Tool.run(newFrontendActionFactory<CmgASTFrontendAction>().get());
    }));
  }

  for (auto &&result : results) {
    result.get();
  }

  return 0;

  // ClangTool Tool(Compilations, SourcePathList);

  // return Tool.run(newFrontendActionFactory<CmgASTFrontendAction>().get());
}